package common

import (
	"encoding/json"
	"fmt"
	"git.myscrm.cn/golang/stark/v4"
	openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
	rds20140815 "github.com/alibabacloud-go/rds-20140815/v4/client"
	util "github.com/alibabacloud-go/tea-utils/v2/service"
	"github.com/alibabacloud-go/tea/tea"
	"strings"
)

const (
	AliYunRdsEndpoint = "rds.aliyuncs.com"
)

// AliyunDbClient 阿里云数据库实例client工具类
type AliyunDbClient struct {
	AccessKeyId     *string
	AccessKeySecret *string
	DBInstanceId    *string
}

// NewAliyunDbClient
// 阿里云数据库实例client工具类
func NewAliyunDbClient() *AliyunDbClient {
	//  ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET 从apollo获取
	//aliyun_rds_access_key_id = LTAI5tLPwHKDiQRFXqLme14Z
	//aliyun_rds_access_key_secret = 5OWucAJVaPGrDqGMj7KLk2HlATOxvl
	//aliyun_rds_instance_id = rm-wz9yi3c0jl9n11893
	return &AliyunDbClient{
		AccessKeyId:     tea.String(stark.Configer.(stark.ApolloConfigerIface).GetStringValue("aliyun_rds_access_key_id", "LTAI5tLPwHKDiQRFXqLme14Z")),
		AccessKeySecret: tea.String(stark.Configer.(stark.ApolloConfigerIface).GetStringValue("aliyun_rds_access_key_secret", "5OWucAJVaPGrDqGMj7KLk2HlATOxvl")),
		DBInstanceId:    tea.String(stark.Configer.(stark.ApolloConfigerIface).GetStringValue("aliyun_rds_instance_id", "rm-wz9yi3c0jl9n11893")),
	}
}

/**
 * CreateClient 使用AK&SK初始化账号Client
 * @param accessKeyId
 * @param accessKeySecret
 * @return Client
 * @throws Exception
 */
func (r *AliyunDbClient) CreateClient(accessKeyId *string, accessKeySecret *string) (_result *rds20140815.Client, _err error) {
	config := &openapi.Config{
		// 必填，您的 AccessKey ID
		AccessKeyId: accessKeyId,
		// 必填，您的 AccessKey Secret
		AccessKeySecret: accessKeySecret,
	}
	// Endpoint 请参考 https://api.aliyun.com/product/Rds
	config.Endpoint = tea.String(AliYunRdsEndpoint)
	_result = &rds20140815.Client{}
	_result, _err = rds20140815.NewClient(config)
	return _result, _err
}

// CreateDatabase 创建数据库
func (r *AliyunDbClient) CreateDatabase(dbName string) (response *rds20140815.CreateDatabaseResponse, _err error) {
	client, _err := r.CreateClient(r.AccessKeyId, r.AccessKeySecret)
	backRes := &rds20140815.CreateDatabaseResponse{}
	if _err != nil {
		return backRes, _err
	}

	createDatabaseRequest := &rds20140815.CreateDatabaseRequest{
		DBInstanceId:     r.DBInstanceId,
		DBName:           tea.String(dbName),
		CharacterSetName: tea.String("utf8mb4"),
	}
	runtime := &util.RuntimeOptions{
		// 超时设置，该产品部分接口调用比较慢，请您适当调整超时时间。
		ReadTimeout:    tea.Int(50000),
		ConnectTimeout: tea.Int(50000),
	}
	backRes, tryErr := func() (res *rds20140815.CreateDatabaseResponse, _e error) {
		defer func() {
			if r := tea.Recover(recover()); r != nil {
				_e = r
			}
		}()
		// API返回值
		backRes, _err = client.CreateDatabaseWithOptions(createDatabaseRequest, runtime)

		if _err != nil {
			return backRes, _err
		}

		return backRes, nil
	}()

	if tryErr != nil {
		var error = &tea.SDKError{}
		if _t, ok := tryErr.(*tea.SDKError); ok {
			error = _t
		} else {
			error.Message = tea.String(tryErr.Error())
		}
		// 错误 message
		fmt.Println(tea.StringValue(error.Message))
		// 诊断地址
		var data interface{}
		d := json.NewDecoder(strings.NewReader(tea.StringValue(error.Data)))
		d.Decode(&data)
		if m, ok := data.(map[string]interface{}); ok {
			recommend, _ := m["Recommend"]
			fmt.Println(recommend)
		}
		_, _err = util.AssertAsString(error.Message)
		if _err != nil {
			return backRes, _err
		}
	}
	return backRes, _err
}

// CreateAccount 创建用户账号
func (r *AliyunDbClient) CreateAccount(account string, password string) (response *rds20140815.CreateAccountResponse, _err error) {
	client, _err := r.CreateClient(r.AccessKeyId, r.AccessKeySecret)
	backAccountRes := &rds20140815.CreateAccountResponse{}
	if _err != nil {
		return backAccountRes, _err
	}

	createAccountRequest := &rds20140815.CreateAccountRequest{
		DBInstanceId:    r.DBInstanceId,
		AccountName:     tea.String(account),
		AccountPassword: tea.String(password),
	}
	runtime := &util.RuntimeOptions{
		// 超时设置，该产品部分接口调用比较慢，请您适当调整超时时间。
		ReadTimeout:    tea.Int(50000),
		ConnectTimeout: tea.Int(50000),
	}
	backAccountRes, tryErr := func() (res *rds20140815.CreateAccountResponse, _e error) {
		defer func() {
			if r := tea.Recover(recover()); r != nil {
				_e = r
			}
		}()
		// API返回值
		backAccountRes, _err = client.CreateAccountWithOptions(createAccountRequest, runtime)

		if _err != nil {
			return backAccountRes, _err
		}

		return backAccountRes, nil
	}()

	if tryErr != nil {
		var error = &tea.SDKError{}
		if _t, ok := tryErr.(*tea.SDKError); ok {
			error = _t
		} else {
			error.Message = tea.String(tryErr.Error())
		}
		// 错误 message
		fmt.Println(tea.StringValue(error.Message))
		// 诊断地址
		var data interface{}
		d := json.NewDecoder(strings.NewReader(tea.StringValue(error.Data)))
		d.Decode(&data)
		if m, ok := data.(map[string]interface{}); ok {
			recommend, _ := m["Recommend"]
			fmt.Println(recommend)
		}
		_, _err = util.AssertAsString(error.Message)
		if _err != nil {
			return backAccountRes, _err
		}
	}
	return backAccountRes, _err
}

// GetAccount 查看用户账号
func (r *AliyunDbClient) GetAccount(account string) (response *rds20140815.DescribeAccountsResponse, _err error) {
	client, _err := r.CreateClient(r.AccessKeyId, r.AccessKeySecret)
	backAccountRes := &rds20140815.DescribeAccountsResponse{}
	if _err != nil {
		return backAccountRes, _err
	}

	getAccountRequest := &rds20140815.DescribeAccountsRequest{
		DBInstanceId: r.DBInstanceId,
	}
	if account != "" {
		getAccountRequest.AccountName = tea.String(account)
	}
	runtime := &util.RuntimeOptions{
		// 超时设置，该产品部分接口调用比较慢，请您适当调整超时时间。
		ReadTimeout:    tea.Int(50000),
		ConnectTimeout: tea.Int(50000),
	}
	backAccountRes, tryErr := func() (res *rds20140815.DescribeAccountsResponse, _e error) {
		defer func() {
			if r := tea.Recover(recover()); r != nil {
				_e = r
			}
		}()
		// API返回值
		backAccountRes, _err = client.DescribeAccountsWithOptions(getAccountRequest, runtime)

		if _err != nil {
			return backAccountRes, _err
		}

		return backAccountRes, nil
	}()

	if tryErr != nil {
		var error = &tea.SDKError{}
		if _t, ok := tryErr.(*tea.SDKError); ok {
			error = _t
		} else {
			error.Message = tea.String(tryErr.Error())
		}
		// 错误 message
		fmt.Println(tea.StringValue(error.Message))
		// 诊断地址
		var data interface{}
		d := json.NewDecoder(strings.NewReader(tea.StringValue(error.Data)))
		d.Decode(&data)
		if m, ok := data.(map[string]interface{}); ok {
			recommend, _ := m["Recommend"]
			fmt.Println(recommend)
		}
		_, _err = util.AssertAsString(error.Message)
		if _err != nil {
			return backAccountRes, _err
		}
	}
	return backAccountRes, _err
}

// GrantAccountPrivilege 授权账号访问数据库
func (r *AliyunDbClient) GrantAccountPrivilege(account string, dbName string, accountPrivilege string) (response *rds20140815.GrantAccountPrivilegeResponse, _err error) {
	client, _err := r.CreateClient(r.AccessKeyId, r.AccessKeySecret)
	backRes := &rds20140815.GrantAccountPrivilegeResponse{}
	if _err != nil {
		return backRes, _err
	}

	grantAccountPrivilegeRequest := &rds20140815.GrantAccountPrivilegeRequest{
		DBInstanceId:     r.DBInstanceId,
		AccountName:      tea.String(account),
		DBName:           tea.String(dbName),
		AccountPrivilege: tea.String(accountPrivilege),
	}

	runtime := &util.RuntimeOptions{
		// 超时设置，该产品部分接口调用比较慢，请您适当调整超时时间。
		ReadTimeout:    tea.Int(50000),
		ConnectTimeout: tea.Int(50000),
	}
	backRes, tryErr := func() (res *rds20140815.GrantAccountPrivilegeResponse, _e error) {
		defer func() {
			if r := tea.Recover(recover()); r != nil {
				_e = r
			}
		}()
		// API返回值
		backRes, _err = client.GrantAccountPrivilegeWithOptions(grantAccountPrivilegeRequest, runtime)

		if _err != nil {
			return backRes, _err
		}

		return backRes, nil
	}()

	if tryErr != nil {
		var error = &tea.SDKError{}
		if _t, ok := tryErr.(*tea.SDKError); ok {
			error = _t
		} else {
			error.Message = tea.String(tryErr.Error())
		}
		// 错误 message
		fmt.Println(tea.StringValue(error.Message))
		// 诊断地址
		var data interface{}
		d := json.NewDecoder(strings.NewReader(tea.StringValue(error.Data)))
		d.Decode(&data)
		if m, ok := data.(map[string]interface{}); ok {
			recommend, _ := m["Recommend"]
			fmt.Println(recommend)
		}
		_, _err = util.AssertAsString(error.Message)
		if _err != nil {
			return backRes, _err
		}
	}
	return backRes, _err
}
